/*
 * TowerRedTwo.java
 *
 * Created on December 19, 2007, 8:43 PM
 *
 * Copyright (C) 2007-2008  Hylke van der Schaaf
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, in version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package hextd.tower;

import hextd.hex.Hex;
import hextd.sprite.EnemySprite;
import hextd.util.Cache;
import hextd.util.Context;
import hextd.util.Geometry;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.util.Vector;

/**
 *
 * @author hylke
 */
public class TowerRedTwo extends TowerBase {
    public static int price = 20000;
    public static int damage = 20000;
    public static float range = 8f;
    public static float spreadRadiusBase = 2f;
    public static float projectileSpeedBase = 0.4f;
    
    private int fireAt = -1;
    private EnemySprite.COLOR damageColor = EnemySprite.COLOR.RED;
    private int coolDown = 0;
    private int coolDownTime = 14;
    
    private Color transColor;
    private float projectileSpeed;
    private float spreadRadius;
    private float spreadRadius2;
    
    private Vector<Projectile> projectiles;
    private BufferedImage[] projectileImg;
    
    /** Creates a new instance of TowerRedTwo */
    public TowerRedTwo(Context context, Hex hex) {
        super(TowerFactory.type.redTwo, price, damage, range);
        this.lineColor = Color.RED;
        this.transColor = new Color(this.lineColor.getRed(), this.lineColor.getGreen(), this.lineColor.getBlue(), 50);
        this.doInit(context, hex);
        this.projectiles = new Vector<Projectile>();
    }
    
    @Override
    public void doTick(int gameTime) {
        if (this.coolDown > 0) {
            this.coolDown--;
        } else {
            int enemyNr = this.findEnemy(this.fireAt, false);
            this.fireAt = enemyNr;
            
            if (enemyNr >= 0) {
                Projectile p = new Projectile();
                p.target = this.context.enemies[enemyNr];
                p.x = this.xFloat;
                p.y = this.yFloat;
                this.projectiles.add(p);
                this.coolDown = this.coolDownTime;
            }
        }
        
        for (int ip=this.projectiles.size()-1; ip >=0; ip--) {
            Projectile p = this.projectiles.get(ip);
            float dx, dy, r, factor;
            if (p.status == 0) {
                dx = p.target.getX() - p.x;
                dy = p.target.getY() - p.y;
                r = (float)Math.sqrt(dx*dx + dy*dy);
                factor = this.projectileSpeed/r;
                if (factor < 1) {
                    dx *= factor;
                    dy *= factor;
                    p.x += dx;
                    p.y += dy;
                } else {
                    // HIT!
                    p.x = p.target.getX();
                    p.y = p.target.getY();
                    p.status = 1;
                }
            }
            if (p.status == 1) {
                p.targetsHit = this.findEnemiesInRange(p.x, p.y, this.spreadRadius);
                int damageBlast;
                float rs;
                EnemySprite enemy;
                for (int i=0; i < p.targetsHit.length; i++) {
                    enemy = p.targetsHit[i];
                    dx = p.x - enemy.getX();
                    dy = p.y - enemy.getY();
                    rs = (float)Math.sqrt(dx*dx + dy*dy);
                    damageBlast = Math.round( this.damageCurrent * (1 - rs/this.spreadRadius) );
                    enemy.doDamage(damageBlast, this.damageColor);
                }
                p.status++;
            } else if (p.status > 1) {
                p.target = null;
                this.projectiles.remove(ip);
            }
        }
    }
    
    @Override
    public String getStatusString() {
        String retString = "";
        retString += "<h1>Red Tower 2</h1>" +
                "<p>" +
                "<b>Level:</b> "+(1+this.level)+"<br>\n" +
                "<b>Damage:</b> "+this.damageText+"<br>\n" +
                "<b>Range:</b> "+this.rangeText+"<br>" +
                "</p>\n";
        return retString;
    }
    
    @Override
    public String getInfoString() {
        String retString = "";
        retString += "<h1>Red Tower 2</h1>" +
                "<p>" +
                "Tower firing fast homing projectiles with a small splash radius. " +
                "When the projectiles lose their target they continue to the last known location and detonate." +
                "<br>Strong against red enemies, very weak against green enemies." +
                "</p>" +
                "<p>" +
                "<b>Price:</b> "+this.form.format(this.price)+"<br>" +
                "<b>Damage:</b> "+this.form.format(this.damageCurrent)+" + splash<br>" +
                "<b>Range:</b> "+this.form.format(rangeCurrent)+"<br>" +
                "<b>Refire rate:</b> 1.25/s"+
                "</p>";
        return retString;
    }
    
    @Override
    protected void generateShapes() {
        Cache cache = this.context.getCache();
        
        float width = this.context.hexPaintWidth;
        int shapeCount = 5;
        this.shapes = new Shape[shapeCount];
        this.shapes[0] = new Ellipse2D.Float(-0.3f*this.paintScale, -0.3f*this.paintScale, 0.6f*this.paintScale, 0.6f*this.paintScale);
        this.shapes[1] = new Ellipse2D.Float(-0.3f*this.paintScale, -0.3f*this.paintScale, 0.6f*this.paintScale, 0.6f*this.paintScale);
        this.shapes[2] = new Ellipse2D.Float(-1.0f*this.context.strokeScale, -1.0f*this.context.strokeScale, 2.0f*this.context.strokeScale, 2.0f*this.context.strokeScale);
        this.shapes[3] = new Line2D.Float( width,  0.5f*this.paintScale,  0.3f*width,  0.15f*this.paintScale);
        this.shapes[4] = new Line2D.Float(-width, -0.5f*this.paintScale, -0.3f*width, -0.15f*this.paintScale);
        
        this.shapeAction = new int[shapeCount];
        this.shapeAction[0] = 2;
        this.shapeAction[1] = 1;
        this.shapeAction[2] = 1;
        this.shapeAction[3] = 1;
        this.shapeAction[4] = 1;
        
        this.shapeColor = new Color[shapeCount];
        this.shapeColor[0] = this.transColor;
        this.shapeColor[1] = this.lineColor;
        this.shapeColor[2] = this.lineColor;
        this.shapeColor[3] = this.lineColor;
        this.shapeColor[4] = this.lineColor;
        
        this.strokes = new Stroke[shapeCount];
        this.strokes[0] = new BasicStroke(2.0f*this.context.strokeScale, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL);
        this.strokes[1] = this.strokes[0];
        this.strokes[2] = this.strokes[0];
        this.strokes[3] = this.strokes[0];
        this.strokes[4] = this.strokes[0];
        this.spreadRadius = this.spreadRadiusBase;
        this.spreadRadius2 = this.spreadRadius * this.spreadRadius;
        this.projectileSpeed = projectileSpeedBase;
        
        if (cache.hasBufImgArr("Red2ProjImagArr")) {
            this.projectileImg = cache.getBufImgArr("Red2ProjImagArr");
        } else {
            float pWidth = width/10f;
            float pScale = this.paintScale/10f;
            int imgW = (int)(pScale*2)+2;
            int imgH = (int)(pScale*2)+2;
            this.projectileImg = new BufferedImage[3];
            float[][] pPoints = Geometry.createPolyCoords(pScale, (float)imgW/2, (float)imgH/2);
            AffineTransform atr = new AffineTransform();
            for (int i=0; i<this.projectileImg.length; i++) {
                atr.setToIdentity();
                atr.rotate(Math.PI * i * 2/6/3, (float)imgW/2, (float)imgH/2);
                
                this.projectileImg[i] = new BufferedImage(imgW, imgH, BufferedImage.TYPE_INT_ARGB_PRE);
                //GeneralPath polyHex = Geometry.coordsToGeneralPath(pPoints, true);
                Graphics2D g2 = this.projectileImg[i].createGraphics();
                g2.transform(atr);
                g2.setColor(this.lineColor);
                //g2.draw(polyHex);
                g2.draw(new Line2D.Float(pPoints[0][0], pPoints[0][1], pPoints[3][0], pPoints[3][1]));
                g2.draw(new Line2D.Float(pPoints[1][0], pPoints[1][1], pPoints[4][0], pPoints[4][1]));
                g2.draw(new Line2D.Float(pPoints[2][0], pPoints[2][1], pPoints[5][0], pPoints[5][1]));
                g2.dispose();
            }
            cache.putBufImgArr("Red2ProjImagArr", this.projectileImg);
        }
        
    }
    
    @Override
    public void paintEffects(Graphics2D g2, int gameTime) {
        Stroke defaultStroke = g2.getStroke();
        
        g2.setColor(this.lineColor);
        
        float pw = (float)this.projectileImg[0].getWidth() / 2f;
        float ph = (float)this.projectileImg[0].getHeight() / 2f;
        for (int ip=0; ip<this.projectiles.size(); ip++) {
            Projectile p = this.projectiles.get(ip);
            if (p.status == 0) {
                g2.drawImage(this.projectileImg[p.anim], Math.round(p.x*paintScale+this.context.offsetX-pw), Math.round(p.y*paintScale+this.context.offsetY-ph), null);
                p.anim++;
                if (p.anim >= this.projectileImg.length) {
                    p.anim = 0;
                }
            } else {
                synchronized(p) {
                    if (p.targetsHit != null) {
                        for (int i=0; i<p.targetsHit.length; i++) {
                            g2.draw(new Line2D.Float( p.x*paintScale+this.context.offsetX, p.y*paintScale+this.context.offsetY, p.targetsHit[i].getPaintX(), p.targetsHit[i].getPaintY() ));
                        }
                    }
                }
            }
        }
        
        g2.setStroke(defaultStroke);
    }
}
